Imports System.IO

Public Class Program

    Public Event Progress(ByVal sender As Object, ByVal e As Emergency_Args)
    Public Event Message(ByVal sender As Object, ByVal e As Emergency_Args)
    Public m_eeprom() As Byte = Nothing
    Public m_baud As Integer = 500000
    Public m_fuseBit As Byte = 46
    Public m_fuseBitHigh As Byte = 200
    Public m_extended As Byte = 127
    Public m_flash() As Byte = Nothing
    Public m_firmware As Byte() = Nothing
    Private m_progress As Integer = 0
    Private m_save As Boolean = False
    Const rst As Byte = 16
    Private m_BLresponse As Byte
    Private m_message As String = ""
    Private bgw As System.ComponentModel.BackgroundWorker
    Private eventArgs As System.ComponentModel.DoWorkEventArgs
    Private m_device_name As String = ""
    Private m_board_name As String = ""
    Private m_program_firmware As Boolean = True

#Region "---------------= Properties"
    Public WriteOnly Property eeprom() As Byte()
        Set(ByVal value As Byte())
            m_eeprom = value
        End Set
    End Property
    Public WriteOnly Property flash() As Byte()
        Set(ByVal value As Byte())
            m_flash = value
        End Set
    End Property
    Public WriteOnly Property firmware() As Byte()
        Set(ByVal value As Byte())
            m_firmware = value
        End Set
    End Property
#End Region
#Region "---------------= Event Handlers"
    Protected Sub OnProgress(ByVal progress As Integer)
        m_progress = progress
        RaiseEvent Progress(Me, New Emergency_Args(progress, m_message))
    End Sub

    Protected Sub OnMessage(ByVal Message As String)
        m_message = Message
        RaiseEvent Message(Me, New Emergency_Args(m_progress, m_message))
    End Sub
#End Region

    Friend Sub New(ByVal Speed As BK_SPEEDS, Optional ByVal device_name As String = "", Optional ByVal board_name As String = "", Optional ByVal auto_program_fw As Boolean = True)
        m_device_name = device_name
        m_board_name = board_name
        m_program_firmware = auto_program_fw
        Select Case Speed
            Case BK_SPEEDS.BK_16MHz
                m_baud = 500000
                m_fuseBit = 46
                m_fuseBitHigh = 200
                m_extended = 127
                m_BLresponse = &HBB
            Case BK_SPEEDS.BK_12MHz
                m_baud = 375000
                m_fuseBit = 46
                m_fuseBitHigh = 200
                m_extended = 127
                m_BLresponse = &HB9
            Case BK_SPEEDS.BK_8MHz
                m_baud = 250000
                m_fuseBit = 36 ' Internal 8MHz BOD enabled and 00 start up time
                m_fuseBitHigh = 216
                m_extended = 127
                m_BLresponse = &HB1
            Case BK_SPEEDS.BK_8MHz_V3
                m_baud = 250000
                m_BLresponse = &HB3
                m_fuseBit = 98 + 128
                m_extended = 253
                m_fuseBitHigh = 216
            Case BK_SPEEDS.BK_12MHz_V3
                m_fuseBitHigh = 216
                m_fuseBit = 96 + 128
                m_baud = 375000
                m_extended = 253
                m_BLresponse = &HB5
            Case BK_SPEEDS.BK_16MHz_V3
                m_fuseBitHigh = 216
                m_fuseBit = 96 + 128
                m_baud = 500000
                m_extended = 253
                m_BLresponse = &HB5
        End Select
    End Sub
    Friend Sub New(ByVal Speed As BK_SPEEDS, ByVal saveEE As Boolean)
        Me.New(Speed)
        m_save = saveEE
    End Sub

    Public Function Execute( _
             ByVal backGroundWorker As System.ComponentModel.BackgroundWorker, _
             ByVal e As System.ComponentModel.DoWorkEventArgs) As Boolean

        ' Store the reference to the BackgroundWorker and the
        ' DoWorkEventArgs objects:
        bgw = backGroundWorker
        eventArgs = e
        Dim ret As Boolean = True
        Dim f_return As Byte() = Nothing

        ReDim Preserve m_flash(4095)

        If SPI_Connect(, m_device_name) Then
            If spi_reset() Then
                'GoTo weee
                chipErase()
                If spi_reset() Then

                    Threading.Thread.Sleep(10)
                    SPI_out(172)
                    SPI_out(160)
                    SPI_in()
                    SPI_out(m_fuseBit)
                    Threading.Thread.Sleep(10)
                    SPI_out(172)
                    SPI_out(168)
                    SPI_in()
                    SPI_out(m_fuseBitHigh)
                    Threading.Thread.Sleep(10)
                    SPI_out(172)
                    SPI_out(164)
                    SPI_in()
                    SPI_out(m_extended)
                    'Threading.Thread.Sleep(10)
                    SPI_out(172)
                    SPI_out(255)
                    SPI_in()
                    'SPI_out(205)
                    SPI_out(&HFF)
                    SPI_disconnect()

                    OnMessage("Programming Flash....")
                    If Not Me.setProgram(m_flash, False, True) Then
                        OnMessage("Failed Flash")
                        ret = False
                    End If

                    OnMessage("Programming EEprom....")
                    If ret And Not IsNothing(m_eeprom) AndAlso Not Me.setEEprom(m_eeprom) Then
                        OnMessage("Failed eeprom")
                        ret = False
                    End If

                    SPI_Connect(, m_device_name)
                    spi_reset()
                    SPI_out(172)
                    SPI_out(255)
                    SPI_in()
                    SPI_out(204)

                    Threading.Thread.Sleep(10)
                    SPI_disconnect()
                    close_bikirom()

                    If ret Then

                        If BikiRom_connect(False, m_board_name) = BK_return.BK_OK Then
                            SetUsbVariable(Biki_USBvars.UV_Baud, m_baud / 1000)
                            close_bikirom()
                        End If

                        'Dim inp As String
                        Dim f_errOr As Int16 = 0
                        If m_program_firmware Then
retryFirmware:

                            OnMessage("Programming Firmware via bootloader")
                            If Not IsNothing(m_firmware) AndAlso Me.program_BootloaderUploadNew(m_board_name) = BK_return.BK_OK Then
                                Try
                                    Dim f_Frame As Comm.Comm_Frame

                                    If BikiRom_Init(True, m_board_name) = BK_return.BK_OK Then
                                        close_bikirom()
                                        'f_Frame = New Comm.Comm_Frame(Comm_Frame.BikiFrameType.ID_CONSULT_INTEGRATED, , Comm_Frame.BikiFrameAction.CMD_STOP)
                                        'If f_Frame.Send(f_return, True) = Comm_Frame.BikiFrameResponse.CMD_OK Then
                                        OnMessage("Init OK!")

                                        ret = True
                                        If m_save Then
                                            Dim inp As String
                                            inp = InputBox("Enter the serial Number written on the back of your BikiRom USB Megaboard", "Serial Number")
                                            If inp <> "" Then
                                                'arrayDump(f_bootloader, "c:\bl-dump.bin")
                                                Dim f_eeDump As New MemoryStream(m_eeprom)
                                                Dim f_eeDump2 As New MemoryStream

                                                CryptFile("This IS! not a TEST moFO But This one IS", f_eeDump, f_eeDump2, True)
                                                arrayDump(f_eeDump2.ToArray, Application.StartupPath & "\" & inp & ".bmd")
                                                MsgBox("Inside the directory you extracted this program is now a file named '" & inp & ".bmd, this needs to be emailed back to me " & _
                                                "at badbiki@ii.net Subject:Board Update return.. cheers", MsgBoxStyle.Information, "Infomation")
                                            End If
                                        End If
                                    Else
                                        OnMessage("Init Not ok! - Possible Board Failure")
                                        ret = False
                                    End If
                                Catch exUsb As USB_exceptions
                                    OnMessage("Init Not ok! - Possible Board Failure")
                                    ret = False
                                Catch exComm As Comm_Exceptions
                                    OnMessage("Init Not ok! - Possible Board Failure")
                                    ret = False
                                End Try

                            Else
                                f_errOr += 1
                                If f_errOr >= 2 Then
                                    OnMessage("Board Programming Failed.. try again")
                                    ret = False
                                Else
                                    GoTo retryFirmware
                                End If
                            End If
                        End If
                        If Not IsNothing(bgw) AndAlso bgw.CancellationPending Then
                            eventArgs.Cancel = True
                        End If
                    End If
                Else
                    ret = False
                    OnMessage("return from reset not OK")
                End If
            Else
                ret = False
                OnMessage("return from reset not OK")
            End If
        Else
            ret = False
            OnMessage("connection not OK")
        End If

        close_bikirom()

        Return ret
    End Function
    Public Sub arrayDump(ByRef sArray() As Byte, ByVal sOutFile As String)
        Dim fStream As New FileStream(sOutFile, FileMode.Create)
        'Dim bWrite As New (fStream)
        fStream.Write(sArray, 0, sArray.Length)
        fStream.Close()
    End Sub
    Public Function setProgram(ByRef a_data() As Byte, ByVal AutoVerify As Boolean, ByVal Program As Boolean) As Boolean
        Dim s_return As Byte
        Dim g, adr As Long
        Dim i As Long
        Dim fnum As Integer = FreeFile()
        Dim spi_enterProgMode As Byte() = {0, rst, 0}
        Dim spi_ProgrammingEnable As Byte() = {172, 83}
        Dim spi_chipErase As Byte() = {172, 128}
        Dim m_error As Integer = 0
        Dim f_genCount As Integer
        Dim f_genCmd(24575) As Byte
        Dim f_return As Integer
        ReDim Preserve a_data(&HFFF)

        If SPI_Connect(, m_device_name) AndAlso spi_reset() Then
            OnMessage("Programing....")
            For i = 126976 To 131071 Step 256
                Console.WriteLine("At the inner loop of " & i, "SPI")
                If Not checkPageEmpty(a_data, i - 126976) Then
                    Console.WriteLine("beyond the Page check " & i, "SPI")
                    If Program = True Then
                        f_genCount = 0
                        For g = i To i + 255 Step 2
restartPageUpload:
                            adr = g \ 2
                            cmd_add(SPI_out_gen(64), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(0), f_genCmd, f_genCount)

                            GoTo skip1
                            If SPI_in() <> 64 Then
                                MsgBox("Out Of Sync LoByte")
                                Console.WriteLine("Lo Byte " & g & "Out Of Sync", "SPI ERROR")
                                m_error += 1
                                If m_error >= 100 Then
                                    OnMessage("serious SPI Programming errors > 100")
                                    Exit Function
                                End If
                                If Not spi_reset() Then Exit Function
                                GoTo restartPageUpload

                            End If
skip1:
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(a_data(g - 126976)), f_genCmd, f_genCount)

                            cmd_add(SPI_out_gen(72), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(0), f_genCmd, f_genCount)
                            GoTo skip2
                            If SPI_in() <> 72 Then
                                MsgBox("Out Of Sync HiByte")
                                Console.WriteLine("Hi Byte " & g & "Out Of Sync", "SPI ERROR")
                                m_error += 1
                                If m_error >= 100 Then
                                    OnMessage("serious error")
                                    Exit Function
                                End If
                                If Not spi_reset() Then Exit Function
                                GoTo restartPageUpload
                                'Exit Sub
                            End If
skip2:
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(a_data(g + 1 - 126976)), f_genCmd, f_genCount)
                        Next

                        FT_Write_Bytes(lngHandle, f_genCmd(0), 24575, f_return)

                        'Write(page)
                        SPI_out(76)
                        SPI_out(HIBYTE(adr))
                        SPI_out(LOBYTE(adr))
                        s_return = SPI_in()
                        'If LOBYTE(adr) <> s_return Then Debug.Print("Potenialy Failing on the Page Write command")
                        If LOBYTE(adr) <> 0 Then Debug.Print("Potenialy Failing on the Page Write command")
                        Debug.Print(s_return)
                        Threading.Thread.Sleep(20)
                    End If
                    ' Verify the memory just written
                    If AutoVerify Then
                        Threading.Thread.Sleep(20)
                        For g = i To i + 255 Step 2
                            adr = g \ 2
                            f_genCount = 0
                            cmd_add(SPI_out_gen(&H20), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(HIBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            FT_Write_Bytes(lngHandle, f_genCmd(0), f_genCount, f_return)
                            ''SPI_out(32)
                            ''SPI_out(HIBYTE(adr))
                            ''SPI_out(LOBYTE(adr))
                            Threading.Thread.Sleep(20)
                            s_return = SPI_in()
                            ''s_return = SPI_in_slow()
                            If s_return <> a_data(g - 126976) Then
                                Console.WriteLine("Error on Verify")
                                Exit Function
                            End If
                            f_genCount = 0
                            cmd_add(SPI_out_gen(&H28), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(HIBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            FT_Write_Bytes(lngHandle, f_genCmd(0), f_genCount, f_return)
                            s_return = SPI_in()
                            's_return = SPI_in_slow()
                            If s_return <> a_data(g - 126976 + 1) Then
                                Console.WriteLine("Error on Verify 2")
                                ' SPI_disconnect()
                                ' Return False
                            End If
                        Next
                    End If
                    OnProgress(((i - 126976) / 4096) * 100)
                End If
            Next
            Return True
        Else
            Return False
        End If
        OnProgress(100)
        SPI_disconnect()
        Exit Function
    End Function
    Private Sub cmd_add(ByRef f_from() As Byte, ByRef f_array() As Byte, ByRef f_count As Integer)
        array_copy(f_from, 0, f_array, f_count, f_from.Length)
        f_count += f_from.Length
    End Sub
    Public Function setEEprom(ByRef s_data() As Byte) As Boolean
        Dim i As Long
        Dim bStatus As Boolean = False
        Dim fnum As Integer = FreeFile()
        Dim spi_enterProgMode As Byte() = {0, rst, 0}
        Dim spi_ProgrammingEnable As Byte() = {172, 83}
        Dim f_sndCmd(95) As Byte
        Dim f_cmdCount As Integer
        Dim f_written As Integer

        If Not IsNothing(s_data) AndAlso SPI_Connect(, m_device_name) AndAlso spi_reset() Then
            Console.WriteLine("Communication OK.. programming", "SPI")
            For i = 0 To 143
                Console.WriteLine("At the inner loop of " & i, "SPI")
                If s_data(i) <> 255 Then
                    Console.WriteLine("beyond the Page check " & i, "SPI")
                    f_cmdCount = 0
                    cmd_add(SPI_out_gen(192), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(HIBYTE(i)), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(LOBYTE(i)), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(s_data(i)), f_sndCmd, f_cmdCount)
                    FT_Write_Bytes(lngHandle, f_sndCmd(0), 96, f_written)
                    Threading.Thread.Sleep(40)
                End If
                OnProgress((i / 143) * 100)
            Next
            bStatus = True
        End If
        SPI_disconnect()

        Return bStatus
    End Function

    Private Function program_BootloaderUploadNew(Optional ByVal device_name As String = "") As BK_return
        If BikiRom_Init(False, device_name) = BK_return.BK_OK Then
            Dim f_Frame As Comm.Comm_Frame
            Dim f_Packet() As Byte = Nothing
            Dim Address As UInt32 = 0
            Dim Length As UInt32 = 0
            Dim cmd() As Byte = Nothing
            Dim f_data As Byte() = Nothing

            BikiRom_Flush()
            BikiRom_BootMode()

            m_BikiInfo.TimeOut = 20

            'Threading.Thread.Sleep(100)

            Try
                f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_BOOTLOADER, , , , Comm.Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC)
                f_Frame.Send(f_Packet, False, 50)

                m_BikiInfo.TimeOut = 8000

                If Not IsNothing(f_Packet) Then
                    Select Case (f_Packet(0))
                        Case &H75, &H73, &H71, &H76, &H78, &H7A
                            f_data = cv_BytesFromHex(m_firmware)
                        Case Else
                            OnMessage("Invalid Bootloader Response")
                            BikiRom_Reset()
                            m_BikiInfo.reset()
                            Return BK_return.BK_FAILED_INIT
                    End Select

                    f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS, , , , Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                    If f_Frame.Send() = Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then

                        While Address < UBound(f_data)
                            Length = (f_data(Address) * &H100) + f_data(Address + 1)

                            ReDim cmd(Length - 3)
                            Array.Copy(f_data, Address + 2, cmd, 0, Length - 2)

                            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_BOOTLOADER, , , cmd, Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                            f_Frame.Send(, , 4)

                            OnProgress((Address / UBound(f_data)) * 100)

                            Address += Length + 2
                        End While

                    Else
                        OnMessage("Bootloader Erasing Failed")
                        BikiRom_Reset()
                        m_BikiInfo.reset()
                        Return BK_return.BK_FIRMWARE
                    End If

                Else
                    BikiRom_Reset()
                    m_BikiInfo.reset()
                    Return BK_return.BK_FIRMWARE
                End If

                BikiRom_Reset()
                m_BikiInfo.reset()
                Return BK_return.BK_OK

            Catch exComm As Comm_Exceptions
                OnMessage(exComm.Description)
                BikiRom_Reset()
                m_BikiInfo.reset()
                Return BK_return.BK_IO_ERROR_BIK
            Catch exUsb As USB_exceptions
                OnMessage(exUsb.Description)
                BikiRom_Reset()
                m_BikiInfo.reset()
                Return BK_return.BK_IO_ERROR_USB
            End Try
        End If
        close_bikirom()
    End Function
   
End Class
